package de.tum.in.msspp.services;

import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

import com.caucho.hessian.client.HessianProxyFactory;

import de.tum.in.msspp.data.FaceRegion;

public class ServiceProvider 
{
	private static String DEFAULT_URL = "http://vmschlichter9.informatik.tu-muenchen.de/msspp/services/";
	private String server_url;
	
	//Available Webservices
	private UserService userService;
	private FaceService faceService;
	private GraphService graphService;
	
	//User data
	private String username;
	private String password;
	
	private Context context;
	
	/**
	 * Create new service provider
	 * @param url - where to find webservices
	 * @param context
	 */
	public ServiceProvider(String url,Context context) 
	{
		this.context = context;
		
		//Check url
		if(url == null)
			this.server_url = DEFAULT_URL;
		else
			this.server_url = url;
		
		//setup service
		this.setupService();
	}
	
	/**
	 * Setup the service
	 * Login, create connection etc.
	 */
	private void setupService()
	{
	    HessianProxyFactory proxyFactory = new HessianProxyFactory();
	    
		try 
		{
			this.userService = (UserService) proxyFactory.create(UserService.class, server_url+"userService", this.context.getClassLoader());
			this.trytologin();//creates new user, if required
			
			//Testing purpose User
			/*
			username = "msspp_4d4410c81a4db";
			password = "lbs_0.07453823485682187";
			*/
			
			
			proxyFactory.setUser(username);
	    	proxyFactory.setPassword(password);
	    	
	    	Log.i("ServiceProvider",username+ " "+ password);
	    	
			this.faceService = (FaceService) proxyFactory.create(FaceService.class, server_url+"faceService", this.context.getClassLoader());
			this.graphService = (GraphService) proxyFactory.create(GraphService.class, server_url+"graphService", this.context.getClassLoader());
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
			Log.i("ServiceProvider", e.getMessage());
		}	
	}
	
	public String getId(){
		return this.username;
	}
	
	/**
	 * Trys to login the user to the server
	 * if no user/password given, one will be created
	 * @throws Exception
	 */
	private void trytologin() throws Exception
	{
		SharedPreferences preferences = this.context.getSharedPreferences("ServiceProvider", Context.MODE_PRIVATE);
		
		this.username = preferences.getString("username", null);
		this.password = preferences.getString("password", null);
		
		//No User found
		if(username == null)
		{
			//Make random password
			Random r = new Random();
			this.password = "lbs_"+r.nextDouble();
	
			this.username = this.userService.register(this.password);
			
			//Save into preferences
			Editor editor = preferences.edit();
			editor.putString("username", this.username);
			editor.putString("password", this.password);
			editor.commit();
			
			Log.i("ServiceProvider", "Registered User:"+this.username+" Password:"+this.password);
		}else{
			//Already found user
			Log.i("ServiceProvider", "Found registered User:"+this.username);
		}
	}
	
	/**
	 * Saves the last logged in user
	 * @param username
	 */
	public void setLastUser(String username)
	{
		SharedPreferences preferences = this.context.getSharedPreferences("ServiceProvider", Context.MODE_PRIVATE);
		Editor editor = preferences.edit();
		editor.putString("lastUser", username);
		editor.commit();
	}
	
	/**
	 * Returns the last logged in user
	 * @return
	 */
	public String getLastUser()
	{

		SharedPreferences preferences = this.context.getSharedPreferences("ServiceProvider", Context.MODE_PRIVATE);
		
		return preferences.getString("lastUser", "");
	}
	
	/**
	 * Returns the recently viewed picture
	 * @return path to picture
	 */
	public String lastViewedPicture()
	{
		SharedPreferences preferences = this.context.getSharedPreferences("ServiceProvider", Context.MODE_PRIVATE);
		
		String path = preferences.getString("recentPicture", null);
		
		return path;
	}
	
	/**
	 * Saves the recentlyUsedPicture
	 * @param path
	 */
	public void setLastViewPicture(String path)
	{
		SharedPreferences preferences = this.context.getSharedPreferences("ServiceProvider", Context.MODE_PRIVATE);
		Editor editor = preferences.edit();
		editor.putString("recentPicture", path);
		editor.commit();
	}
	
	/**
	 * Sends a message to server
	 * @param receiver - identifies the receiver of the message
	 * @param message - message content
	 * @return succeed
	 */
	public boolean sendMessage(String receiver, String message)
	{
		boolean succeed = this.userService.sendMessage(receiver, message);
		
		Log.i("ServiceProvider","	Send message '"+message+"' succeeded:"+succeed);
		
		return succeed;
	}
	
	/**
	 * Returns all message found on the server for the current user
	 * @return List of all message found
	 */
	public List<String> getMessages()
	{
		List<String> messages = this.userService.collectMessages();
		
		Log.i("ServiceProvider","	Received "+messages.size()+" messages");
		
		return messages;
	}
	
	/* Face Service */
	
	/**
	 * Tries to detect faces at the given image
	 * @param image - image to search
	 */
	public List<FaceRegion> detectFaces(Bitmap image)
	{
		//Get image raw data
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG,100, stream);
		byte[] imageData = stream.toByteArray();
		
		//Get found face regions
		List<FaceRegion> regions = null;
		
		try 
		{
			regions = this.faceService.detectFaces(imageData);
		} catch (Exception e) {
			Log.i("ServiceProvider", "Fehler "+ e.getMessage());
		}
		
		//Log
		if(regions!=null)
			Log.i("ServiceProvider", "		Found regions: "+regions.size());
		else
			Log.i("ServiceProvider", "Returned Null");
		
		return regions;
	}
	
	/**
	 * Tries to classifiy faces
	 * @param image to classify
	 * @return a List of classified faceregions
	 */
	public List<FaceRegion> classifyDetectedFaces(Bitmap image)
	{
		//Get image raw data
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG,100, stream);
		byte[] imageData = stream.toByteArray();
		
		
		List<FaceRegion> regions = null;
		
		//Get classified regions
		try 
		{
			regions = this.faceService.detectAndClassifyFaces(imageData);
		} catch (Exception e) {
			Log.i("ServiceProvider", "Fehler: "+e.getMessage());
		}
		
		//Log
		if(regions!=null)
			for(FaceRegion region:regions)
				Log.i("---------------Person found------------------", ""+region.personId);
			//Log.i("ServiceProvider", "		Found classified regions: "+regions.size());
		else
			Log.i("ServiceProvider", "Returned Null classified");
		
		return regions;
	}
	
	/**
	 * Classifies a single face
	 * @param image with the face region
	 * @return classified personid
	 * @throws Exception
	 */
	public int classifiyFace(Bitmap image) throws Exception
	{
		//Get raw image data
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG,100, stream);
		byte[] imageData = stream.toByteArray();
		
		//Try to classifiy
		Integer user = null;
		
		try 
		{
			user = this.faceService.classifyFace(imageData);
		} catch (Exception e) {
			Log.e("ServiceProvider", e.getMessage());
		}
		
		if(user == null)
			throw new Exception("Unable to classify Face");
		
		return user.intValue();
	}
	
	/**
	 * Trains the server with the given face
	 * @param user - personid
	 * @param image - face image
	 */
	public void trainFace(int user,Bitmap image)
	{
		Log.i("ServiceProvider", "Train with userId:"+user);
		
		//Get raw image data
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG,100, stream);
		byte[] imageData = stream.toByteArray();
		
		//Train server
		try 
		{
			this.faceService.addTrainingData(user, imageData);
		} catch (Exception e) {
			Log.e("ServiceProvider", e.getMessage());
		}
	}
	
	/* Graph Service */
	
	/**
	 * Sends the graph to the server and creates a graphical version
	 * @param xml - xml version of the graph
	 * @retrun the image of the graph
	 */
	public Bitmap sendGraph(String xml)
	{
		try{
			byte[] graphData = graphService.renderGraph(xml);
			return BitmapFactory.decodeByteArray(graphData, 0, graphData.length);
		}catch(Exception e){
			Log.i("ServiceProvider", "Fehler "+e.getMessage());
		}
		
		return null;
	}
}
